#include <iostream>
#include <cassert>
#include <typeinfo>

class Any
{
private:
    class holder
    {
    public:
        virtual ~holder() {}
        virtual const std::type_info &type() = 0;
        virtual holder *clone() = 0;
    };

    template <class T>
    class placeholder : public holder
    {
    public:
        placeholder(const T &val) : _val(val) {}                     // 构造
        virtual const std::type_info &type() { return typeid(T); }   // 获取子类对象保存的数据类型
        virtual holder *clone() { return new placeholder<T>(_val); } // 针对当前对象自身，克隆一个新的子类对象

    public:
        T _val;
    };

    holder *_content; // 父类指针，接收子类对象，子类对象可以是任意类型

public:
    Any() : _content(nullptr){}; // 默认构造
    ~Any() { delete _content; }  // 析构

    template <class T>
    Any(const T &val) : _content(new placeholder<T>(val)) {}
    // （other._content ? other._content->clone() : nullptr）   如果other._content不为空 则克隆一个子类对象 否则返回nullptr
    Any(const Any &other) : _content(other._content ? other._content->clone() : nullptr) {}

    template <class T>
    Any &operator=(const T &val)
    {
        // 现代写法的赋值拷贝
        Any(val).swap(*this);
        return *this;
    }

    Any &operator=(const Any &other)
    {
        // 现代写法的赋值拷贝
        Any(other).swap(*this);
        return *this;
    }

    // 获取子类对象保存的数据的地址
    template <class T>
    T *get()
    {
        // 想要获取的类型必须和子类对象保存的数据的类型一样
        assert(typeid(T) == _content->type());
        return &((placeholder<T> *)_content)->_val;
    }

    // 用于赋值拷贝
    Any &swap(Any &other)
    {
        std::swap(other._content, _content);
        return *this;
    }
};

class Test
{
public:
    Test()
    {
        std::cout << "构造" << std::endl;
    }

    Test(const Test &t)
    {
        std::cout << "拷贝构造" << std::endl;
    }

    ~Test()
    {
        std::cout << "析构" << std::endl;
    }
};

int main()
{
    Any a;
    a = 10;
    int *pa = a.get<int>();
    std::cout << *pa << std::endl;

    std::string s = "abcd";
    a = s;
    std::string *temp = a.get<std::string>();
    std::cout << *temp << std::endl;

    Test t;
    a = t;

    return 0;
}